/*
 * Copyright (c) 2020 hebeiyiliuba.com
 * All rights reserved.
 *
 */
package org.jeecg.modules.third.aliyunocr;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.third.aliyunocr.utils.HttpUtils;
import org.jeecg.modules.wlhy.hyconfig.entity.HyConfig;
import org.jeecg.modules.wlhy.utils.HyConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.google.api.client.util.Base64.encodeBase64;

/**
 * AliyunOCR识别服务
 *
 * @author duanlikao
 * @created 2021/1/29
 */
@Service
public class AliyunOcrService {


   // private  static  final String ALIYUN_OCR_APPCODE = "c5dffe50bc2e4d108858be6adc73b700";

    private static final Logger LOGGER = LoggerFactory.getLogger(AliyunOcrService.class);

    /**
     * 身份证识别
     *
     * @param imgFile
     * @param side 身份证正反面类型:face/back
     * @return
     */
    public  String ocrIdcard(String imgFile ,String side){
        HyConfig systemConfig = HyConfigUtils.getConfig();
        if(systemConfig == null || !systemConfig.getAliyunOcrIzUse()){
            LOGGER.info("AliyunOCR识别服务暂未开启,请联系管理员。");
            return StringUtils.EMPTY;
           // throw new JeecgBootException("AliyunOCR识别服务暂未开启,请联系管理员。");
        }
        String host = "http://dm-51.data.aliyun.com";
        String path = "/rest/160601/ocr/ocr_idcard.json";

        Map <String, String> headers = new HashMap <>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + systemConfig.getAliyunOcrAppcode());
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/json; charset=UTF-8");

        Map<String, String> querys = new HashMap<>();
        // 对图像进行base64编码
        String imgBase64 = img_base64(imgFile);

        //configure配置
        JSONObject configObj = new JSONObject();
        configObj.put("side", side);
        String config_str = configObj.toString();
        // 拼装请求body的json字符串
        JSONObject requestObj = new JSONObject();
        requestObj.put("image", imgBase64);
        if(configObj.size() > 0) {
            requestObj.put("configure", config_str);
        }
        String bodys = requestObj.toString();
//        LOGGER.info("AliyunOcrService ocrIdcard url :{} bodys :{}",host +path, bodys);
        try {
            HttpResponse response = HttpUtils.doPost(host, path, "POST", headers, querys, bodys);
            int stat = response.getStatusLine().getStatusCode();
            if(stat != 200){
                if(stat == 403){
                    LOGGER.info(" AliyunOcrService ocrIdcard  Quota Exhausted: 套餐包次数用完");
                }else if(stat == 463){
                    LOGGER.info(" AliyunOcrService ocrIdcard  Invalid Input - wrong category: 上传图像不是对应服务的图像，如身份证服务请求的不是身份证");
                    throw new JeecgBootException("上传图像不是对应服务的图像，如身份证服务请求的不是身份证!");
                }
                LOGGER.info("AliyunOcrService ocrIdcard Http code: :{}  | http header error msg:{} | Http body error msg: ",
                        stat, response.getFirstHeader("X-Ca-Error-Message"),EntityUtils.toString(response.getEntity()));
                return null ;
            }
            String res = EntityUtils.toString(response.getEntity());
            JSONObject res_obj = JSON.parseObject(res);
//            LOGGER.info("AliyunOcrService ocrIdcard res_obj :{} ",res_obj.toJSONString());
            return res_obj.toJSONString();

        } catch (Exception e) {
            LOGGER.info("AliyunOcrService ocrIdcard Exception :{} ",e.getMessage());
        }
        return null;
    }

    /**
     * 对path进行判断，如果是本地文件就二进制读取并base64编码，如果是url,则返回
     * @param path
     * @return
     */
    private static String img_base64(String path) {
        LOGGER.info("开始转base64,地址为"+path);
        String imgBase64=null;
        if (path.startsWith("http")){
            imgBase64 = path;
        }else {
            try {
                File file = new File(path);
                byte[] content = new byte[(int) file.length()];
                FileInputStream finputstream = new FileInputStream(file);
                finputstream.read(content);
                finputstream.close();
                imgBase64 = new String(encodeBase64(content));
            } catch (IOException e) {
                LOGGER.info("AliyunOcrService img_base64 IOException :{} ",e.getMessage());
                return imgBase64;
            }
        }

        return imgBase64;
    }

    /**
     * 驾驶证识别
     * @param imgFile
     * @param side #首页/副页:face/back
     * @return
     */
    public  String  ocrDriver(String imgFile ,String side){

        HyConfig systemConfig = HyConfigUtils.getConfig();
        if(systemConfig == null || !systemConfig.getAliyunOcrIzUse()){
            LOGGER.info("AliyunOCR识别服务暂未开启,请联系管理员。");
            return StringUtils.EMPTY;
            // throw new JeecgBootException("AliyunOCR识别服务暂未开启,请联系管理员。");
        }

        String host = "https://dm-52.data.aliyun.com";
        String path = "/rest/160601/ocr/ocr_driver_license.json";


        boolean is_old_format = false;//如果文档的输入中含有inputs字段，设置为True， 否则设置为False
        //请根据线上文档修改configure字段
        JSONObject configObj = new JSONObject();
        configObj.put("side", side);
        String config_str = configObj.toString();
        Map<String, String> headers = new HashMap<>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " +  systemConfig.getAliyunOcrAppcode() );

        Map<String, String> querys = new HashMap<>();

        // 对图像进行base64编码
        String imgBase64 = "";
        try {
            File file = new File(imgFile);
            byte[] content = new byte[(int) file.length()];
            FileInputStream finputstream = new FileInputStream(file);
            finputstream.read(content);
            finputstream.close();
            imgBase64 = new String(encodeBase64(content));
        } catch (IOException e) {
            LOGGER.info("AliyunOcrService ocrDriver IOException :{} ",e.getMessage());
            return null;
        }
        // 拼装请求body的json字符串
        JSONObject requestObj = new JSONObject();
        try {
            if(is_old_format) {
                JSONObject obj = new JSONObject();
                obj.put("image", getParam(50, imgBase64));
                if(config_str.length() > 0) {
                    obj.put("configure", getParam(50, config_str));
                }
                JSONArray inputArray = new JSONArray();
                inputArray.add(obj);
                requestObj.put("inputs", inputArray);
            }else{
                requestObj.put("image", imgBase64);
                if(config_str.length() > 0) {
                    requestObj.put("configure", config_str);
                }
            }
        } catch (JSONException e) {
            LOGGER.info("AliyunOcrService ocrDriver JSONException :{} ",e.getMessage());

        }
        String bodys = requestObj.toString();
        LOGGER.debug("AliyunOcrService ocrDriver url :{} bodys :{}",host +path, bodys);
        try {
            HttpResponse response = HttpUtils.doPost(host, path, "POST", headers, querys, bodys);
            int stat = response.getStatusLine().getStatusCode();
            if(stat != 200){
                LOGGER.info("AliyunOcrService ocrDriver Http code: {}  | http header error msg:{} | Http body error msg: ",
                        stat, response.getFirstHeader("X-Ca-Error-Message"),EntityUtils.toString(response.getEntity()));
                return null;
            }

            String res = EntityUtils.toString(response.getEntity());
            JSONObject res_obj = JSON.parseObject(res);
            if(is_old_format) {
                JSONArray outputArray = res_obj.getJSONArray("outputs");
                String output = outputArray.getJSONObject(0).getJSONObject("outputValue").getString("dataValue");
                JSONObject out = JSON.parseObject(output);
//                LOGGER.info("AliyunOcrService ocrDriver 正常请求获取返回的json :{}  ",out.toJSONString());
                return  out.toJSONString();
            }else{
//                LOGGER.info("AliyunOcrService ocrDriver res_obj :{} ",res_obj.toJSONString());
                return  res_obj.toJSONString();
            }
        } catch (Exception e) {
            LOGGER.info("AliyunOcrService ocrDriver Exception :{} ",e.getMessage());
        }
        return null;
    }

    /**
     * 行驶证识别
     * #正反面类型face/back
     * @param imgFile
     * @param side
     * @return
     */
    public String ocrVehicle(String imgFile ,String side ){

        HyConfig systemConfig = HyConfigUtils.getConfig();
        if(systemConfig == null || !systemConfig.getAliyunOcrIzUse()){
            LOGGER.info("AliyunOCR识别服务暂未开启,请联系管理员。");
            return StringUtils.EMPTY;
            // throw new JeecgBootException("AliyunOCR识别服务暂未开启,请联系管理员。");
        }

        String host = "https://dm-53.data.aliyun.com";
        String path = "/rest/160601/ocr/ocr_vehicle.json";

        boolean is_old_format = false;//如果文档的输入中含有inputs字段，设置为True， 否则设置为False
        //请根据线上文档修改configure字段
        JSONObject configObj = new JSONObject();
        configObj.put("side", side);
        String config_str = configObj.toString();
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " +  systemConfig.getAliyunOcrAppcode() );
        Map<String, String> querys = new HashMap<String, String>();

        // 对图像进行base64编码
        String imgBase64 = "";
        try {
            File file = new File(imgFile);
            byte[] content = new byte[(int) file.length()];
            FileInputStream finputstream = new FileInputStream(file);
            finputstream.read(content);
            finputstream.close();
            imgBase64 = new String(encodeBase64(content));
        } catch (IOException e) {
            LOGGER.info("AliyunOcrService ocrVehicle IOException :{} ",e.getMessage());
            return null ;
        }
        // 拼装请求body的json字符串
        JSONObject requestObj = new JSONObject();
        try {
            if(is_old_format) {
                JSONObject obj = new JSONObject();
                obj.put("image", getParam(50, imgBase64));
                if(config_str.length() > 0) {
                    obj.put("configure", getParam(50, config_str));
                }
                JSONArray inputArray = new JSONArray();
                inputArray.add(obj);
                requestObj.put("inputs", inputArray);
            }else{
                requestObj.put("image", imgBase64);
                if(config_str.length() > 0) {
                    requestObj.put("configure", config_str);
                }
            }
        } catch (JSONException e) {
            LOGGER.info("AliyunOcrService ocrVehicle JSONException :{} ",e.getMessage());
        }
        String bodys = requestObj.toString();
        LOGGER.debug("AliyunOcrService ocrVehicle url :{} bodys :{}",host +path, bodys);
        try {
            HttpResponse response = HttpUtils.doPost(host, path, "POST", headers, querys, bodys);
            int stat = response.getStatusLine().getStatusCode();
            if(stat != 200){
                LOGGER.info("AliyunOcrService ocrVehicle Http code: {}  | http header error msg:{} | Http body error msg: ",
                        stat, response.getFirstHeader("X-Ca-Error-Message"),EntityUtils.toString(response.getEntity()));
                return null;
            }

            String res = EntityUtils.toString(response.getEntity());
            JSONObject res_obj = JSON.parseObject(res);
            if(is_old_format) {
                JSONArray outputArray = res_obj.getJSONArray("outputs");
                String output = outputArray.getJSONObject(0).getJSONObject("outputValue").getString("dataValue");
                JSONObject out = JSON.parseObject(output);
//                LOGGER.info("AliyunOcrService ocrVehicle 正常请求获取返回的json :{}  ",out.toJSONString());
                return out.toJSONString();
            }else{
//                LOGGER.info("AliyunOcrService ocrVehicle res_obj :{} ",res_obj.toJSONString());
                return res_obj.toJSONString();
            }
        } catch (Exception e) {
            LOGGER.info("AliyunOcrService ocrVehicle Exception :{} ",e.getMessage());
        }
        return null;
    }

    /*
     * 获取参数的json对象
     */
    private static JSONObject getParam(int type, String dataValue) {
        JSONObject obj = new JSONObject();
        try {
            obj.put("dataType", type);
            obj.put("dataValue", dataValue);
        } catch (JSONException e) {
            LOGGER.info("AliyunOcrService getParam JSONException :{} ",e.getMessage());
        }
        return obj;
    }

    public static void main(String[] args) {
        HyConfig config = new HyConfig();
        config.setAliyunOcrIzUse(true);
        config.setAliyunOcrAppcode("c5dffe50bc2e4d108858be6adc73b700");
        HyConfigUtils.setConfig(config);

        AliyunOcrService aliyunOcrService= new AliyunOcrService();
        String side = "front" ;
        side = side.equals("front") ? "face": "back";

//        String frontfile = "/Users/duanlikao/Downloads/1侯相科/微信图片_20201027103911.jpg";
//        String frontString = aliyunOcrService.ocrIdcard(frontfile,side);
//        System.out.println(frontString);

//        String frontfile = "/Users/duanlikao/Downloads/1侯相科/微信图片_20201027104139.png";
//        String frontString = aliyunOcrService.ocrDriver(frontfile,side);
//        System.out.println(frontString);

/*        String frontfile = "/Users/duanlikao/Downloads/1侯相科/微信图片_202010271039114.jpg";
        String frontString = aliyunOcrService.ocrVehicle(frontfile,side);
        System.out.println(frontString);*/

        //error
        //{"status":"205","msg":"身份证号输入错误，身份证号不标准","name":"贾*","idCard":"13************701X","accountNo":"62*************0428","bank":"","cardName":"","cardType":"","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230324160841_1213bk3n_a523d7ee"}
//        {"status":"02","msg":"验证不通过，身份信息或手机号输入不正确","name":"贾*","idCard":"13************703X","accountNo":"62*************0429","bank":"","cardName":"","cardType":"","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230324160937_54c9bk3n_8b2f3a23"}
        //{"status":"02","msg":"验证不通过，身份信息或手机号输入不正确","name":"贾*","idCard":"13************703X","accountNo":"62*************0428","bank":"","cardName":"","cardType":"","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230324161043_79a7bk3n_5346cf69"}
        //{"status":"01","msg":"验证通过","name":"薛*","idCard":"14************5914","accountNo":"62*************2571","bank":"中国农业银行","cardName":"金穗通宝卡(银联卡)","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165406_e34bbk3n_d453c565"}
        String json = null;
//        json =  aliyunOcrService.ToolsBank( "13052119861022703X" ,  "贾肖飞", "6212260406006720428"); //中国工商银行
//        json =  aliyunOcrService.ToolsBank( "13052119861022703X" ,  "贾肖肖飞", "6212260406006720428"); //中国工商银行
//        System.out.println(json);
//        json = aliyunOcrService.ToolsBank( "142326198202115914" ,  "薛聪明", "6228483038626062571");//中国银行
//        json = aliyunOcrService.ToolsBank( "142625197801093310" ,  "牛保科", "6217858100035309546");//中国银行
//        System.out.println(json);

//        json = aliyunOcrService.ToolsBank( "370829197704102016" ,  "郝同修", "6217002210004280951");//中国建设银行
//        System.out.println(json);

//        json = aliyunOcrService.ToolsBank( "230227197912061515" ,  "宋金福", "6228480188463635279");//中国农业银行
//        System.out.println(json);

//        json = aliyunOcrService.ToolsBank( "34242619770706521X" ,  "曾庆国", "6225887865607465");//招商银行
//        System.out.println(json);
//
//        json = aliyunOcrService.ToolsBank( "130521198904056299" ,  "赵沿民", "622908443085836712");//兴业银行
//        System.out.println(json);
//
//        json = aliyunOcrService.ToolsBank( "410183197909106531" ,  "徐建国", "6222620620029357620");//交通银行
//        System.out.println(json);
//
//        json = aliyunOcrService.ToolsBank( "37082919881027211X" ,  "朱艳敏", "6215824610008680215");//邮政储蓄银行
//        System.out.println(json);

//        {"status":"01","msg":"验证通过","name":"薛*","idCard":"14************5914","accountNo":"62*************2571","bank":"中国农业银行","cardName":"金穗通宝卡(银联卡)","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165406_e34bbk3n_d453c565"}
//        {"status":"01","msg":"验证通过","name":"郝*","idCard":"37************2016","accountNo":"62*************0951","bank":"中国建设银行","cardName":"龙卡通","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165407_e1c0bk3n_ccea7cfb"}
//        {"status":"01","msg":"验证通过","name":"宋*","idCard":"23************1515","accountNo":"62*************5279","bank":"中国农业银行","cardName":"金穗通宝卡(银联卡)","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165408_9b1abk3n_9a9d2c69"}
//        {"status":"01","msg":"验证通过","name":"薛*","idCard":"14************5914","accountNo":"62*************2571","bank":"中国农业银行","cardName":"金穗通宝卡(银联卡)","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165409_2527bk3n_9aceb4fd"}
//        {"status":"01","msg":"验证通过","name":"曾*","idCard":"34************521X","accountNo":"62**********7465","bank":"招商银行","cardName":"一卡通(银联卡)","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165409_89cebk3n_1da87002"}
//        {"status":"01","msg":"验证通过","name":"赵*","idCard":"13************6299","accountNo":"62************6712","bank":"兴业银行","cardName":"兴业自然人生理财卡","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165411_7b49bk3n_616ae9e1"}
//        {"status":"01","msg":"验证通过","name":"徐*","idCard":"41************6531","accountNo":"62*************7620","bank":"交通银行","cardName":"交银IC卡","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165412_1f2cbk3n_2648bc15"}
//        {"status":"01","msg":"验证通过","name":"朱*","idCard":"37************211X","accountNo":"62*************0215","bank":"中国邮政储蓄银行","cardName":"福农卡","cardType":"借记卡","sex":"","area":"","province":"","city":"","prefecture":"","birthday":"","addrCode":"","lastCode":"","traceId":"20230323165414_9a8bbk3n_2f7400ff"}

    }


    /**
     * 银联三要验证素
     * @param idCard
     * @param name
     * @param accountNo
     * @return
     */
    public Result<?> ToolsBank(String idCard , String name, String accountNo) {
        HyConfig systemConfig = HyConfigUtils.getConfig();
        if (systemConfig == null || !systemConfig.getAliyunOcrIzUse()) {
            return Result.error(-1, "银行卡校验服务暂未开启,请联系管理员。");
        }

        String host = "https://tbank.market.alicloudapi.com";// 【1】请求地址 支持http 和 https 及 WEBSOCKET
        String path = "/bank3CheckNew";  // 【2】后缀
        //        String idCard = "511126******064713";// 【4】请求参数，详见文档描述
        //        String name = "杨过";// 【4】请求参数，详见文档描述
        //        String accountNo = "600000******01313";// 【4】请求参数，详见文档描述
        String retErrorString = null;
        try {
            String urlSend = host + path + "?idCard=" + idCard + "&name=" + URLEncoder.encode(name, "UTF-8") + "&accountNo=" + accountNo;  // 【5】拼接请求链接
            URL url = new URL(urlSend);
            HttpURLConnection httpURLCon = (HttpURLConnection) url.openConnection();
            httpURLCon.setRequestProperty("Authorization", "APPCODE " + systemConfig.getAliyunOcrAppcode());// 格式Authorization:APPCODE (中间是英文空格)
            int httpCode = httpURLCon.getResponseCode();
            if (httpCode == 200) {
                String json = read(httpURLCon.getInputStream());
//                LOGGER.debug("AliyunOcrService ToolsBank 正常请求获取返回的json :{}  ",json);
                JSONObject jsonObject = JSONObject.parseObject(json);
                String status = jsonObject.getString("status");
                if ("01".equals(status)) {
                    return Result.OK(jsonObject);
                }
                String msg = jsonObject.getString("msg");
                return Result.error(-2, msg);
            } else {
                Map<String, List<String>> map = httpURLCon.getHeaderFields();
                String error = map.get("X-Ca-Error-Message").get(0);
                if (httpCode == 400 && error.equals("Invalid AppCode `not exists`")) {
                    LOGGER.info("AliyunOcrService ToolsBank Invalid AppCode `not exists`: AppCode错误  ");
                    retErrorString = "AppCode错误";
                } else if (httpCode == 400 && error.equals("Invalid Url")) {
                    LOGGER.info("AliyunOcrService ToolsBank Invalid Url: 请求的 Method、Path 或者环境错误  ");
                    retErrorString = "请求的 Method、Path 或者环境错误 ";
                } else if (httpCode == 400 && error.equals("Invalid Param Location")) {
                    LOGGER.info("AliyunOcrService ToolsBank Invalid Param Location: 参数错误  ");
                    retErrorString = "参数错误";
                } else if (httpCode == 403 && error.equals("Unauthorized")) {
                    LOGGER.info("AliyunOcrService ToolsBank Unauthorized :服务未被授权（或URL和Path不正确）   ");
                    retErrorString = "服务未被授权（或URL和Path不正确）";
                } else if (httpCode == 403 && error.equals("Quota Exhausted")) {
                    LOGGER.info(" AliyunOcrService ToolsBank bank3CheckNew Quota Exhausted: 套餐包次数用完");
                    retErrorString = "套餐包次数用完";
                } else {
                    LOGGER.info("AliyunOcrService ToolsBank 参数名错误 或 其他错误 :{}   ", error);
                    retErrorString = error;
                }
            }
        } catch (Exception e) {
            // 打开注释查看详细报错异常信息
            LOGGER.error("AliyunOcrService ToolsBank URL地址错误 UnknownHostException :{}   ", e.getMessage());
            retErrorString = e.getMessage();
        }
        return Result.error(-3, retErrorString);
    }

    /*
     * 读取返回结果
     */
    private static String read(InputStream is) throws IOException {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line = null;
        while ((line = br.readLine()) != null) {
            line = new String(line.getBytes(), "utf-8");
            sb.append(line);
        }
        br.close();
        return sb.toString();
    }







}
